#pragma once

#include "WSHeaders.h"
#include "WSBaseTypes.h"
#include "WSNode.h"

WS_NS_CORE_BEGIN

class WSNode;

class WS_DLL WSAction
{
	WSPtrProperty(WSNode, Target);
	WSPtrProperty(WSNode, OriginalTarget);
	WSProperty(string, Tag);
public:
	WSAction();
	virtual ~WSAction();
	virtual bool IsFinish();
	virtual void StartWithTarget(WSNode* pTarget);
	virtual void Stop();
	virtual void Update(float progress) = 0;
	virtual void Step(float deltaTime) = 0;
};

class WS_DLL WSFiniteTimeAction : public WSAction
{
	WSProperty(float, Duration);
public:
	WSFiniteTimeAction() : _Duration(0)
	{}

	virtual ~WSFiniteTimeAction() {}
};

class WS_DLL WSInstantAction : public WSFiniteTimeAction
{
public:
	WSInstantAction();
	~WSInstantAction() {};

	virtual bool IsFinish();
	virtual void Step(float dt);
	virtual void Update(float progress) = 0;
};

class WS_DLL WSShow : public WSInstantAction
{
public:
	WSShow() {}
	virtual ~WSShow() {}

	virtual void Update(float progress);
};

class WS_DLL WSHide : public WSInstantAction
{
public:
	WSHide() {}
	virtual ~WSHide() {}

	virtual void Update(float progress);
};

class WS_DLL WSPlace : public WSInstantAction
{
	WSReadOnlyProperty(WSPoint, Position);
public:
	WSPlace() : _Position(0.f, 0.f) {}
	WSPlace(const WSPoint& point) : _Position(point) {}
	WSPlace(float x, float y) : _Position(x, y) {}

	virtual ~WSPlace() {}
	virtual void Update(float progress);
};

class WS_DLL WSIntervalAction : public WSFiniteTimeAction
{
	WSReadOnlyProperty(float, Elapsed);
public:
	WSIntervalAction() : WSFiniteTimeAction() {}
	WSIntervalAction(float duration);

	virtual bool IsFinish();
	virtual void Step(float dt);
	virtual void StartWithTarget(WSNode* pTarget);

private:
	bool _isFirstTick;
};

class WS_DLL WSSequence : public WSIntervalAction
{
public:
	WSSequence(WSFiniteTimeAction* pActionOne, WSFiniteTimeAction* pActionTwo);
	virtual ~WSSequence();

	virtual void StartWithTarget(WSNode* pTarget);
	virtual void Stop();
	virtual void Update(float t);
	
protected:
	WSFiniteTimeAction* _pActions[2];
	float _split;
	int _last;
};

class WS_DLL WSRepeat : public WSIntervalAction
{
	WSPtrProperty(WSFiniteTimeAction, InnerAction);
public:
	WSRepeat(WSFiniteTimeAction* pAction, unsigned int times);
	virtual ~WSRepeat();

	virtual void StartWithTarget(WSNode *pTarget);
	virtual void Stop();
	virtual void Update(float dt);
	virtual bool IsFinish();

protected:
	unsigned int _times;
	unsigned int _total;
	float _nextDt;
	bool _actionInstant;
};

class WS_DLL WSRotateTo : public WSIntervalAction
{
public:
	WSRotateTo(float duration, float deltaAngle);
	WSRotateTo(float duration, float deltaAngleX, float deltaAngleY);

	virtual void StartWithTarget(WSNode* pTarget);
	virtual void Update(float progress);

protected:
	float _endAngleX;
	float _startAngleX;
	float _diffAngleX;

	float _endAngleY;
	float _startAngleY;
	float _diffAngleY;
};

class WS_DLL WSRotateBy : public WSIntervalAction
{
public:
	WSRotateBy(float duration, float deltaAngle);
	WSRotateBy(float duration, float deltaAngleX, float deltaAngleY);

	virtual void StartWithTarget(WSNode* pTarget);
	virtual void Update(float progress);

protected:
	float _angleX;
	float _startAngleX;

	float _angleY;
	float _startAngleY;
};

class WS_DLL WSMoveBy : public WSIntervalAction
{
public:
	WSMoveBy(float duration, const WSPoint& delta);

	virtual void StartWithTarget(WSNode* pTarget);
	virtual void Update(float progress);
protected:
	WSMoveBy();

protected:
	WSPoint _deltaPosition;
	WSPoint _startPosiiton;
	WSPoint _previousPosition;

};

class WS_DLL WSMoveTo : public WSMoveBy
{
public:
	WSMoveTo(float duration, const WSPoint& pos);

	virtual void StartWithTarget(WSNode* pTarget);

protected:
	WSMoveTo();

protected:
	WSPoint _endPosition;
};

class WS_DLL WSJumpBy : public WSIntervalAction
{
public:
	WSJumpBy(float duration, const WSPoint& position, float height, unsigned int jumps);

	virtual void StartWithTarget(WSNode* pTarget);
	virtual void Update(float progress);

protected:
	WSPoint _startPoint;
	WSPoint _delta;
	float _height;
	unsigned int _jumps;
	WSPoint _previousPos;
};

class WS_DLL WSJumpTo : public WSJumpBy
{
public:
	virtual void StartWithTarget(WSNode* pTarget);
};

class WS_DLL WSScaleTo : public WSIntervalAction
{
public:
	WSScaleTo(float duration, float s);
	WSScaleTo(float duration, float sx, float sy);

	virtual void StartWithTarget(WSNode* pTarget);
	virtual void Update(float progress);

protected:
	float _scaleX;
    float _scaleY;
    float _startScaleX;
    float _startScaleY;
    float _endScaleX;
    float _endScaleY;
    float _deltaX;
    float _deltaY;
};

class WS_DLL WSScaleBy : public WSScaleTo
{
public:
	virtual void StartWithTarget(WSNode* pTarget);
};

class WS_DLL WSBlink : public WSIntervalAction
{
public:
	WSBlink(float duration, unsigned int blinks);

	virtual void StartWithTarget(WSNode* pTarget);
	virtual void Update(float progress);
	virtual void Stop();

protected:
	unsigned int _times;
	bool _originalState;
};

class WS_DLL WSFadeIn : public WSIntervalAction
{
public:
	virtual void Update(float progress);
};

class WS_DLL WSFadeOut : public WSIntervalAction
{
public:
	virtual void Update(float progress);
};

class WS_DLL WSFadeTo : public WSIntervalAction
{
public:
	WSFadeTo(float duration, BYTE opacity);

	virtual void StartWithTarget(WSNode* pTarget);
	virtual void Update(float progress);

protected:
	BYTE _toOpacity;
	BYTE _fromOpacity;
};

class WSTexture;
class WSAnimation;
class WSSpriteFrame;

class WS_DLL WSAnimate : public WSIntervalAction
{
public:
	WSAnimate(WSAnimation* pAnimation);
	virtual ~WSAnimate();

	virtual void StartWithTarget(WSNode* pTarget);
	virtual void Stop();
	virtual void Update(float t);

private:
	WSArray<float>* _pSplitTimes;
	int				_nextFrame;
	WSSpriteFrame*	_originalFrame;
	unsigned int	_executedLoops;
};

typedef struct
{
	WSArray<WSAction>	Actions;
	WSNode*				Target;
	unsigned int		ActionIndex;

}ActionManagerItem;

WS_NS_CORE_END